#include "HelloWorldScene.h"
#include "scene1.h"

#include "InputsManager.h"
#include "CustomButton.h"

#include "SpriteHelperLoader.h"
#include "LevelHelperLoader.h"

#include "CameraController.h"

#include "stdio.h"
#include "stdlib.h"

#include <CCTransition.h>

#include "../cocosExtension/cocosExtension.h"

USING_NS_CC;

#define RAND(MIN,MAX) ((rand()%((MAX)-(MIN))) + (MIN))

#define PTM_RATIO 32
enum 
{
	kTagTileMap = 1,
	kTagSpriteManager = 1,
	kTagAnimation1 = 1,
}; 

CCScene* HelloWorld::scene()
{
	// 'scene' is an autorelease object
	CCScene *scene = CCScene::node();
	
	// 'layer' is an autorelease object
	HelloWorld *layer = HelloWorld::node();

	// add layer as a child to scene
	scene->addChild(layer);

	// return the scene
	return scene;
}

HelloWorld::HelloWorld()
{
	world = NULL;
	copyOfWorld = NULL;
	groundBody = NULL;

	GuiLayer = NULL;
	GameLayer = NULL;

	player = NULL;
	
	camController = NULL;
    
	lh = NULL;

    m_debugDraw = NULL;
}
HelloWorld::~HelloWorld()
{
	GuiLayer->setIsTouchEnabled( false );
	INPUTS->DeleteVirtualKey( );

	delete player;
	delete camController;
	delete m_debugDraw;
	delete lh;

	
	std::vector<b2Body*> lbody;
	for (b2Body* b = world->GetBodyList(); b; b = b->GetNext())
	{
		lbody.push_back( b );
	}
	for( int i=0; i< lbody.size(); i++ )
	{
		world->DestroyBody( lbody[i] );
	}
	lbody.clear();
	
	delete world;
}

// on "init" you need to initialize your instance
bool HelloWorld::init()
{
	//////////////////////////////
	// 1. super init first
	if ( !CCLayer::init() )
	{
		return false;
	}

	srand( time(NULL) );

	
	GuiLayer = new CCLayer();
	GuiLayer->init();

	GameLayer = new CCLayer();
	GameLayer->init();
	

	//GuiLayer = CCLayer::node();
	//GameLayer = CCLayer::node();

	this->addChild( GameLayer, 50 );
	this->addChild( GuiLayer, 250 );
	/////////////////////////////
	// 2. add a menu item with "X" image, which is clicked to quit the program
	//    you may modify it.

	// add a "close" icon to exit the progress. it's an autorelease object
	CCMenuItemImage *pCloseItem = CCMenuItemImage::itemFromNormalImage(
										"CloseNormal.png",
										"CloseSelected.png",
										GuiLayer,
										menu_selector(HelloWorld::menuCloseCallback) );
	pCloseItem->setPosition( ccp( CCDirector::sharedDirector()->getWinSize().width - 20, CCDirector::sharedDirector()->getWinSize().height - 20) );
  
	

	INPUTS->CreateVirtualKey( GuiLayer );

	// create menu, it's an autorelease object
	CCMenu* pMenu = CCMenu::menuWithItems(pCloseItem,/*pLeftItem, pRightItem, pJumpItem, pRunItem ,*/ NULL);
	pMenu->setPosition( CCPointZero );
	GuiLayer->addChild(pMenu, 1);

	GuiLayer->setIsTouchEnabled( true );
	//this->setIsTouchEnabled( true );
	/////////////////////////////
	// 3. add your codes below...

	// add a label shows "Hello World"
	// create and initialize a label
	CCLabelTTF* pLabel = CCLabelTTF::labelWithString("Hello World", "Thonburi", 34);

	// ask director the window size
	CCSize size = CCDirector::sharedDirector()->getWinSize();

	// position the label on the center of the screen
	pLabel->setPosition( ccp(size.width / 2, size.height - 20) );

	// add the label as a child to this layer
	GameLayer->addChild(pLabel, 1);

	// add "HelloWorld" splash screen"
	CCSprite* pSprite = CCSprite::spriteWithFile("HelloWorld.png");

	// position the sprite on the center of the screen
	pSprite->setPosition( ccp(size.width/2, size.height/2) );

	// add the sprite as a child to this layer
	GameLayer->addChild(pSprite, 0);

	

	// physics

	initPyshicsWorld();
	initPyshicsPlayer();
    
    //copyOfWorld = world->DeepCopy();
    
    
    m_debugDraw = new GLESDebugDraw( PTM_RATIO );
    
    world->SetDebugDraw(m_debugDraw);
   // copyOfWorld->SetDebugDraw(m_debugDraw);
    
    unsigned int flags = 0;
   // flags += b2DebugDraw::e_shapeBit;
   // flags += b2DebugDraw::e_jointBit;
    flags += b2DebugDraw::e_aabbBit;
   // flags += b2DebugDraw::e_pairBit;
   // flags += b2DebugDraw::e_centerOfMassBit;
    m_debugDraw->SetFlags(flags);

    
	camController = new CameraController();
	camController->init( GameLayer );
	camController->setTarget( player->getNode() );
	
	
	// test parralax 
	CCSprite* pSprite2 = NULL;
	CCPoint _p;
	/*
	pSprite2 = CCSprite::spriteWithFile("sol.png");
	pSprite2->setPosition( ccp(size.width/2, size.height/2) );
	_p =  CCPoint( 1.0f, 1.0f );
	camController->addParralaxLayer( _p, true, false )->addChild( pSprite2  );
	*/
	pSprite2 = CCSprite::spriteWithFile("nuage.png");
	pSprite2->setPosition( ccp(size.width/2, size.height/2) );
	_p =  CCPoint( 0.9f, 0.9f );
	camController->addParralaxLayer( _p, true, false )->addChild( pSprite2  );
	
	pSprite2 = CCSprite::spriteWithFile("montagne.png");
	pSprite2->setPosition( ccp(size.width/2, size.height/2) );
	_p =  CCPoint( 0.7f, 1.0f );
	camController->addParralaxLayer( _p, true, false )->addChild( pSprite2  );
	
	pSprite2 = CCSprite::spriteWithFile("ciel.png");
	pSprite2->setPosition( ccp(size.width/2, size.height/2) );
	_p =  CCPoint( 0.3f, 0.3f );
	camController->addParralaxLayer( _p, true, true )->addChild( pSprite2  );
	
	// test parralax 
	

	//LevelHelperLoader levelhelper("levelTest.plhs");
	//lh = new LevelHelperLoader("level1.plhs");
	//lh->addObjectsToWorld( world, GameLayer );


	camController->setUnfollowZone( CCRect( 240.0f, 100.0f, 0.0f, 0.0f ) );

	//GameLayer->setScale( 2.0f );
	// update
    
   // CCTouchDispatcher::sharedDispatcher()->addTargetedDelegate( this, 0, false );
	
	
	
	scheduleUpdate();


	//this->runAction( CCRepeatForever::actionWithAction( CCGravityGrid::actionWithGrid( 10, 5 ) ) );

	return true;
}

void HelloWorld::initPyshicsPlayer()
{
	player = new Player();
	player->init( GameLayer, world );
}

void HelloWorld::initPyshicsWorld()
{
	CCSize screenSize = CCDirector::sharedDirector()->getWinSize();

	// Define the gravity vector.
	b2Vec2 gravity;
	gravity.Set(0.0f, 0.0f);


	const float XSize = screenSize.width * 10.0f;
	const float YSize = screenSize.height * 2.0f;


	// Do we want to let bodies sleep?
	bool doSleep = true;

	// Construct a world object, which will hold and simulate the rigid bodies.
	world = new b2World(gravity, doSleep);

			
	world->SetContinuousPhysics(true);
    

/*
	m_debugDraw = new GLESDebugDraw( PTM_RATIO );
	world->SetDebugDraw(m_debugDraw);
	
	uint flags = 0;
	flags += b2DebugDraw::e_shapeBit;
	flags += b2DebugDraw::e_jointBit;
	flags += b2DebugDraw::e_aabbBit;
	flags += b2DebugDraw::e_pairBit;
	flags += b2DebugDraw::e_centerOfMassBit;
	m_debugDraw->SetFlags(flags);		
*/
	
	
	b2BodyDef groundBodyDef;
	groundBodyDef.position.Set(0, 0); // bottom-left corner
	groundBody = world->CreateBody(&groundBodyDef);
	

	b2PolygonShape groundBox;		
	
	// bottom
	groundBox.SetAsEdge(b2Vec2(0, (30.0f/PTM_RATIO) ), b2Vec2( XSize/PTM_RATIO, (30.0f/PTM_RATIO) ));
	groundBody->CreateFixture(&groundBox, 0);
	
	// top
	groundBox.SetAsEdge(b2Vec2(0,YSize/PTM_RATIO), b2Vec2( XSize/PTM_RATIO, YSize/PTM_RATIO));
	groundBody->CreateFixture(&groundBox, 0);
	
	// left
	groundBox.SetAsEdge(b2Vec2(0,YSize/PTM_RATIO), b2Vec2(0,0));
	groundBody->CreateFixture(&groundBox, 0);
	
	// right
	groundBox.SetAsEdge(b2Vec2( XSize/PTM_RATIO, YSize/PTM_RATIO), b2Vec2( XSize/PTM_RATIO,0) );
	groundBody->CreateFixture(&groundBox, 0);


	// other
//	groundBox.SetAsEdge(b2Vec2((screenSize.width/2.0f)/PTM_RATIO,(screenSize.height/2.0f)/PTM_RATIO), b2Vec2(screenSize.width/PTM_RATIO,(screenSize.height/2.0f)/PTM_RATIO));
	//groundBody->CreateFixture(&groundBox, 0);
	
	/*
	for(int i=0; i<100; i++ )
	{
		CCPoint _pos = CCPoint( RAND( 0, (int)XSize ), RAND( (int)(YSize/4), (int)YSize ) );
		CCSize _size =  CCSize( RAND( 0, (int)(XSize/20.0f) ),  RAND( 0, 2 ) );

		groundBox.SetAsEdge(b2Vec2( _pos.x/PTM_RATIO, _pos.y/PTM_RATIO), b2Vec2( (_pos.x+_size.width)/PTM_RATIO, (_pos.y+_size.height)/PTM_RATIO));
		groundBody->CreateFixture(&groundBox, 0);
	}
	*/
}

void HelloWorld::draw()
{
	return;
	//return;
    // Default GL states: GL_TEXTURE_2D, GL_VERTEX_ARRAY, GL_COLOR_ARRAY, GL_TEXTURE_COORD_ARRAY
	// Needed states:  GL_VERTEX_ARRAY, 
	// Unneeded states: GL_TEXTURE_2D, GL_COLOR_ARRAY, GL_TEXTURE_COORD_ARRAY

	/*
     glDisable(GL_TEXTURE_2D);
	glDisableClientState(GL_COLOR_ARRAY);
	glDisableClientState(GL_TEXTURE_COORD_ARRAY);
	
    world->DrawDebugData();
	copyOfWorld->DrawDebugData();
	
	// restore default GL states
	glEnable(GL_TEXTURE_2D);
	glEnableClientState(GL_COLOR_ARRAY);
	glEnableClientState(GL_TEXTURE_COORD_ARRAY);
    
    
    return;
	*/
    
    
    
    // debug
	b2Fixture* tmp = groundBody->GetFixtureList();
	CCPoint offset = GameLayer->getPosition();
	while( tmp )
	{
		if( tmp->GetType() == b2Shape::e_circle )
		{
			ccDrawCircle( CCPoint( tmp->GetAABB().GetCenter().x *PTM_RATIO + offset.x  , tmp->GetAABB().GetCenter().y *PTM_RATIO + offset.y ), tmp->GetAABB().GetExtents().x *PTM_RATIO, 0.0f, 20, false );
		}
		else
		{
			ccDrawLine( CCPoint( tmp->GetAABB().lowerBound.x *PTM_RATIO + offset.x  , tmp->GetAABB().lowerBound.y *PTM_RATIO + offset.y ) ,
						CCPoint( tmp->GetAABB().upperBound.x *PTM_RATIO + offset.x  , tmp->GetAABB().lowerBound.y *PTM_RATIO + offset.y )  );

			ccDrawLine( CCPoint( tmp->GetAABB().upperBound.x *PTM_RATIO + offset.x  , tmp->GetAABB().lowerBound.y *PTM_RATIO + offset.y ) ,
						CCPoint( tmp->GetAABB().upperBound.x *PTM_RATIO + offset.x  , tmp->GetAABB().upperBound.y *PTM_RATIO + offset.y )  );

			ccDrawLine( CCPoint( tmp->GetAABB().upperBound.x *PTM_RATIO + offset.x  , tmp->GetAABB().upperBound.y *PTM_RATIO + offset.y ) ,
						CCPoint( tmp->GetAABB().lowerBound.x *PTM_RATIO + offset.x  , tmp->GetAABB().upperBound.y *PTM_RATIO + offset.y  )  );

			ccDrawLine( CCPoint( tmp->GetAABB().lowerBound.x *PTM_RATIO + offset.x  , tmp->GetAABB().upperBound.y *PTM_RATIO + offset.y ) ,
						CCPoint( tmp->GetAABB().lowerBound.x *PTM_RATIO + offset.x  , tmp->GetAABB().lowerBound.y *PTM_RATIO + offset.y )  );
		}
			
		tmp = tmp->GetNext();
    }
    
	

    

	player->draw( camController->getCamPos() );

	INPUTS->draw();

    glColor4f( 1.0f, 1.0f, 0.0f, 1.0f);
    /*
    for (b2Body* b = copyOfWorld->GetBodyList(); b; b = b->GetNext())
	{
        tmp = b->GetFixtureList();
        while( tmp )
        {
            if( tmp->GetType() == b2Shape::e_circle )
            {
                ccDrawCircle( CCPoint( tmp->GetAABB().GetCenter().x *PTM_RATIO  , tmp->GetAABB().GetCenter().y *PTM_RATIO ), tmp->GetAABB().GetExtents().x *PTM_RATIO, 0.0f, 20, false );
            }
            else
            {
                ccDrawLine( CCPoint( tmp->GetAABB().lowerBound.x *PTM_RATIO  , tmp->GetAABB().lowerBound.y *PTM_RATIO ) ,
                           CCPoint( tmp->GetAABB().upperBound.x *PTM_RATIO  , tmp->GetAABB().lowerBound.y *PTM_RATIO )  );
                
                ccDrawLine( CCPoint( tmp->GetAABB().upperBound.x *PTM_RATIO  , tmp->GetAABB().lowerBound.y *PTM_RATIO ) ,
                           CCPoint( tmp->GetAABB().upperBound.x *PTM_RATIO  , tmp->GetAABB().upperBound.y *PTM_RATIO )  );
                
                ccDrawLine( CCPoint( tmp->GetAABB().upperBound.x *PTM_RATIO  , tmp->GetAABB().upperBound.y *PTM_RATIO ) ,
                           CCPoint( tmp->GetAABB().lowerBound.x *PTM_RATIO  , tmp->GetAABB().upperBound.y *PTM_RATIO )  );
                
                ccDrawLine( CCPoint( tmp->GetAABB().lowerBound.x *PTM_RATIO  , tmp->GetAABB().upperBound.y *PTM_RATIO ) ,
                           CCPoint( tmp->GetAABB().lowerBound.x *PTM_RATIO  , tmp->GetAABB().lowerBound.y *PTM_RATIO )  );
            }
			
            tmp = tmp->GetNext();
        }
	}
    */
    return;
	/*
	pLeftItem->drawBoundingBox();
	pRightItem->drawBoundingBox();
	pJumpItem->drawBoundingBox();
	pRunItem->drawBoundingBox();
	*/
}

void HelloWorld::update(ccTime dt)
{
	//CCDirector::sharedDirector()->replaceScene( scene1::scene() );

	//It is recommended that a fixed time step is used with Box2D for stability
	//of the simulation, however, we are using a variable time step here.
	//You need to make an informed choice, the following URL is useful
	//http://gafferongames.com/game-physics/fix-your-timestep/

	

	INPUTS->update( dt );

	/*
    INPUTS->SetKeyPress( KEY_ID::KEY_LEFT, pLeftItem->isSelected() );
    INPUTS->SetKeyPress( KEY_ID::KEY_RIGHT, pRightItem->isSelected() );
    INPUTS->SetKeyPress( KEY_ID::KEY_JUMP, pJumpItem->isSelected() );
    INPUTS->SetKeyPress( KEY_ID::KEY_RUN, pRunItem->isSelected() );
    */
	
	int velocityIterations = 8;
	int positionIterations = 1;

	// Instruct the world to perform a single step of simulation. It is
	// generally best to keep the time step and iterations fixed.
	world->Step(dt, velocityIterations, positionIterations);
	
   // copyOfWorld->Step( dt, velocityIterations, positionIterations );
    
	//Iterate over the bodies in the physics world
	for (b2Body* b = world->GetBodyList(); b; b = b->GetNext())
	{
		if (b->GetUserData() != NULL) {
			//Synchronize the AtlasSprites position and rotation with the corresponding body
			CCSprite* myActor = (CCSprite*)b->GetUserData();
			myActor->setPosition( CCPointMake( b->GetPosition().x * PTM_RATIO, b->GetPosition().y * PTM_RATIO) );
			myActor->setRotation( -1 * CC_RADIANS_TO_DEGREES(b->GetAngle()) );
		}	
	}


	player->update( dt );

	camController->update( dt );
	//camController->setCamPos( player->getPixelPosition().x - 240.0f , 0.0f  );
	//GameLayer->setPosition( CCPoint( 240.0f - player.getPixelPosition().x, GameLayer->getPosition().y ) );
}



bool HelloWorld::ccTouchBegan(CCTouch* touch, CCEvent* event)
{
	CCPoint touchLocation = touch->locationInView(touch->view());
	touchLocation = CCDirector::sharedDirector()->convertToGL(touchLocation);

	printf(" touch begin in hello world \n " );
    
	return false;
}
void HelloWorld::ccTouchEnded(CCTouch* touch, CCEvent* event)
{
}
void HelloWorld::ccTouchCancelled(CCTouch *touch, CCEvent* event)
{
}
void HelloWorld::ccTouchMoved(CCTouch* touch, CCEvent* event)
{
}




void HelloWorld::menuCloseCallback(CCObject* pSender)
{
	//unscheduleUpdate();
	//CCTouchDispatcher::sharedDispatcher()->removeDelegate( this );

	//delete this;

	CCTransitionGravityGrid *trans = CCTransitionGravityGrid::transitionWithDuration( 5,  scene1::scene() );
	CCDirector::sharedDirector()->replaceScene( trans );

	//trans->release();
	/*
    delete m_debugDraw;
    
	CCDirector::sharedDirector()->end();

#if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)
	exit(0);
#endif
	*/
}
